﻿(function ($) {
    /**
     * 缓存名称
     * @type {string}
     * @private
     */
    var _cacheName = 'uiMenu';
    /**
     * @class 菜单组件
     * @constructor uiMenu
     * @summary 构造函数
     * @param [options] {Object|String} 组件配置参数|要调用的组件方法名
     * @param [param] {Object} 表示要调用的组件方法的参数
     * @returns {jQuery} jQuery对象
     * @example
     *  //采用默认值
     * $('#menu_simple').uiMenu();
     * //设置组件参数
     *  $('#menu_simple').uiMenu({maxWidth:'200',minWidth:'100'});
     * //调用组件方法
     *  $('#menu_simple').uiMenu('show',this);
     */
    $.fn.uiMenu = function (options, param) {
        if (typeof options == 'string') {
            return $.fn.uiMenu.methods[options](this, param);
        }
        return this.each(function(){
            var me = $(this);
            var cache = me.data(_cacheName);

            options = options || {};
            if (cache) {
                $.extend(cache.options, options);
            } else {
                me.data(_cacheName, {
                    options: $.extend({}, $.fn.uiMenu.defaults, me.parseUIConfig(), options)
                });
            }
            _init(me);
        });
    };
    /**
     * 方法
     * @lends uiMenu.prototype
     */
    $.fn.uiMenu.methods = {
        /**
         * @summary 获取所有配置
         * @param target
         * @returns {Json}
         * @example
         *  $('#btn').uiMenu('options');
         */
        options: function (target) {
            return $.data(target[0], _cacheName).options;
        },
        /**
         * @summary 显示menu，menu不会自己显示，必须调用show方法才能显示
         * @name uiMenu#show
         * @function
         * @param triggerObject 触发显示事件的对象，如点击的button触发的就是button对象
         * @example
         * //通过点击button显示menu
         *  $('#btn').click(function(){
        *     $('#menu_simple').uiMenu('show',this);
        *});
         */
        show: function (target, triggerObject) {
            return _show(target, triggerObject);
        },
        /**
         * @summary 隐藏组件
         * @name uiMenu#hide
         * @function
         * @returns {jQuery} 方法调用者
         */
        hide: function (target) {
            return _hide({data:target});
        },
        /**
         * @summary 将某个menuitem设置为disabled，设置之后menuitem将不会触发事件，如果有子菜单将不能打开子菜单，必须有menuItem。
         * @name uiMenu#disableItem
         * @function
         * @param itemId menuItem的ID
         * @example
         * //调用disableItem方法
         *  $('#btn').click(function(){
        *     $('#menu_simple').uiMenu('disableItem','001');
        *});
         */
        disableItem: function (target, itemId) {
            return _disableItem(target, itemId);
        },
        /**
         * @summary 将某个menuitem设置为enable。
         * @name uiMenu#enableItem
         * @function
         * @param itemId menuItem的ID
         * @example
         * //调用enableItem方法
         *  $('#btn').click(function(){
        *     $('#menu_simple').uiMenu('enableItem','001');
        *});
         */
        enableItem: function (target, itemId) {
            return _enableItem(target, itemId);
        },
        /**
         * @summary 移除组件
         * @name uiMenu#destroy
         * @function
         * @returns {jQuery} 方法调用者
         */
        destroy: function () {
            return _destroy();
        }
    };
    /**
     * 默认配置
     * @lends uiMenu.prototype
     */
    $.fn.uiMenu.defaults =
    {
        /**
         * @summary 是否为右键菜单
         * @type Boolean
         * @default false
         * @example
         * $("#menu_1").uiMenu({contextMenu:true});
         */
        contextMenu: false,

        /**
         * @summary 最大宽度，如果menuItem文字长度超出了最大宽度，将会隐藏，鼠标移动到上面会有全文提示
         * @type Number
         * @default 200
         * @example
         * $("#menu_1").uiMenu({maxWidth:150});
         */
        maxWidth: 200,

        /**
         * @summary 最小宽度，如果menuItem文字长度少于minWidth，则将使用空白填充。
         * @type Number
         * @default 100
         * @example
         * $("#menu_1").uiMenu({minWidth:50});
         */
        minWidth: 100,

        /**
         * @summary 数据源，可以设置为json数据，也可以是url，如果不设置则为local，默认使用页面的dom元素生成Menu
         * @type String
         * @default local
         * @example
         * $("#menu_1").uiMenu({dataSource:'menuData.json'});
         */
        dataSource: 'local',

        /**
         * @summary 当点击选择menu的时候触发的事件，item包含当前menuItem的所有数据。
         * @name uiMenu#onSelect
         * @event
         * @param item 当前menuItem的所有数据
         * @param event jQuery.Event对象
         * @type Function
         * @default 无
         * @example
         * $("#menu_1").uiMenu({
        *         onSelect:function(item,event){
        *            location.href = item.url;
        *         }
        * });
         */
        onSelect: function (item, event) {
        }
    };
    //////--------------------------------内部方法------------------------------
    /**
     * 初始化
     * @param target 目标对象
     */
    var _init = function (target) {
        var options = $.data(target[0], _cacheName).options;
        target.setElemID();
        target.css({"minWidth": options.minWidth, "maxWidth": options.maxWidth});
        if (_IEunder6) {
            target.css("width", options.minWidth);
        }
        if (_IE && webUI_browser().version == 7) {
            target.css("width", options.maxWidth);
        }
        _create(target);
        return target;
    };
    var _create = function (target) {
        // uiMenu 对 options 重设置支持不够全面，实际上也无多大必要
        var options = $.data(target[0], _cacheName).options;
        var source = options.dataSource;
        target.addClass('ui_menu-container ui_menu-content');
        target.css('position', 'absolute');
        if (source) {
            if (source != 'local') {
                if (typeof source == 'string') {
                    _ajaxLoad(target, source);
                } else if (typeof source == 'object') {
                    target.append(_appendNodes(target, source));
                    _bindEvent(target);
                }
            } else {
                var firstMenu = target.children("ul").addClass("ui_menu");
                _parseDuiMenu(target, firstMenu);
                _bindEvent(target);
            }
        }
    };
    var _show = function (target, trigger) {
        var options = $.data(target[0], _cacheName).options;
        var top, left;
        var triggerObject;
        if (trigger.triggerObject) {
            triggerObject = trigger.triggerObject;
            options.triggerData = trigger.triggerData;
        } else {
            triggerObject = trigger;
        }
        var offSet = $(triggerObject).offset();
        if (options.contextMenu) {
            options.triggerObject = triggerObject.target;
            top = triggerObject.pageY;
            left = triggerObject.pageX;
            triggerObject.preventDefault();
            triggerObject.stopPropagation();
            triggerObject.cancelBubble = true; //IE
        } else {
            var bottomWidth = parseInt($(triggerObject).css('borderBottomWidth'));
            top = offSet.top + $(triggerObject).height() + (bottomWidth != 'NaN' ? bottomWidth : 0) + 1; //1px作为调节距离
            left = offSet.left + 1;
        }
        var parent = target.parent();
        while (parent.css('position') == 'static' && parent[0].nodeName != 'BODY') {
            parent = parent.parent();
        }
        top -= parent.offset().top;
        left -= parent.offset().left;

        target.children("ul.ui_menu").show();
        var width = target.width() * 0.7;
        target.children("ul.ui_menu").children().each(function (index, li) {
            var lic = $(li);
            var lic_first = lic.find("span:first");
            if (lic_first.hasClass('ui_menu-item-sep')) {
                lic_first.width('98%'); //分隔条宽度
            } else {
                if (lic_first.width() > width) {
                    lic_first.width(lic.attr('aria-haspopup') ? width - 15 : width);
                }
            }
        });
        if ((left + target.outerWidth()) > document.documentElement.clientWidth) { //当右边距离过短的时候会将提示框调整到左边
            left = left - target.outerWidth() - 5;
        }
        if ((top + target.outerHeight()) > document.documentElement.clientHeight) { //当下边距离过短的时候会将提示框调整到上边
            top = top - target.outerHeight() - 5;
        }
        target.css({"top": top, 'left': left}).show();
        $(document).bind('mousedown.uiMenu',target, _hide);
        return target;
    };
    var _disableItem = function (target, itemId) {
        target.find("#" + itemId)
            .addClass("ui_menu-disabled")
            .unbind(".menuItem");
        return target;
    };
    var _enableItem = function (target, itemId) {
        var cli = target.find("#" + itemId);
        cli.removeClass("ui_menu-disabled");
        _bindLiEvent(target, cli);
        return target;
    };
    var _destroy = function () {
        var $doc = $(document),
            handler;
        while (handler = this.globalEvent.pop()) {
            $doc.unbind(".uiMenu", handler);
        }
    };
    var _ajaxLoad = function (target, source) {
        $.ajax({
            url: source,
            method: 'GET',
            dataType: 'json',
            showLoading:false,
            success: function (data) {
                target.append(_appendNodes(target, data));
                _bindEvent(target);
                return false;
            }
        });
    };
    var _appendNodes = function (target, source, index) {
        var menuHtml = [];
        var ulClass = (index == undefined) ? 'ui_menu' : 'ui_menu-content';
        var display = (index == undefined) ? 'block' : 'none';
        var imgClass =  'ui_menu-icon';
        menuHtml.push('<ul class="' + ulClass + '" style="display:' + display + ';">');
        var childrenHtml = [];
        $(source).each(function (index, item) {
            var liID = target.getElemID() + '_' + item.id;

            function createItemHtml() {
                var itemHtml = [];
                if (item.icon || item.fontIcon) {
                    if (item.fontIcon && !_IEunder6) {
                        item.fontIcon.size = item.fontIcon.size || 16;
                        item.fontIcon.color = item.fontIcon.color || 'inherit';
                        itemHtml.push('<span class="fa ui_menu-icon ' + item.fontIcon.icon + '" style="color:' + item.fontIcon.color + ';font-size:' + item.fontIcon.size + 'px;"></span>');
                    } else {
                        itemHtml.push('<span class="icon ' + imgClass + ' icon_' + item.icon + '"></span>');
                    }
                    itemHtml.push('<span class="ui_menu-text">' + item.label + '</span>');
                }else{
                    itemHtml.push('<span class="ui_menu-text" style="margin-left:2em;">' + item.label + '</span>');
                }
                return itemHtml.join('');
            }

            if (item.children != null) {
                if (item.disabled === true || item.disabled == "true") {
                    childrenHtml.push('<li id="' + liID + '" aria-haspopup="true"  class="ui_menu-disabled">');
                } else {
                    childrenHtml.push('<li id="' + liID + '"  aria-haspopup="true">');
                }
                childrenHtml.push('<a href="javascript:void(0)" class="ui_menu-indicator">');
                //--TO-DO
                childrenHtml.push(createItemHtml());
                childrenHtml.push('<span class="icon ui_menu-popup" role="popup"></span>');
                childrenHtml.push('</a>');
                childrenHtml.push(_appendNodes(target, item.children, index++));
                childrenHtml.push("</li>");
            } else {
                if (item.disabled === true || item.disabled == "true") {
                    childrenHtml.push('<li id="' + liID + '"  class="ui_menu-disabled">');
                } else {
                    childrenHtml.push('<li id="' + liID + '" >');
                }
                childrenHtml.push('<a href="javascript:void(0)" class="ui_menu-indicator">');
                //--TO-DO
                childrenHtml.push(createItemHtml());
                childrenHtml.push('</a>');
                childrenHtml.push('</li>');
            }
            if (item.seperator == "true" || item.seperator == true) {
                childrenHtml.push('<li class="ui_menu-sep-li"  ><span class="ui_menu-item-sep">&nbsp;</span></li>');
            }
            $.data(target[0], liID, item);
        });
        menuHtml.push(childrenHtml.join(''));
        menuHtml.push('</ul>');
        return menuHtml.join('');
    };

    //处理页面编写dom节点的情况
    var _parseDuiMenu = function (target, element) {
        if (element.parent().attr("aria-haspopup") == "true") { //判断是否为第一帧
            element.addClass("ui_menu-content");
        }
        element.css('display', 'none');
        var lis = element.children();
        for (var i = 0; i < lis.length; i++) {
            var li = $(lis[i]), liCul = li.children("ul");
            liCul.remove();
            var label = li.text();
            li.empty();
            if (liCul.length) {
                li.append(liCul);
            }
            var liOpts = li.parseUIConfig();
            var liID = target.getElemID() + '_' + liOpts.id;
            li[0].id = liID;
            $.data(target[0], liID, liOpts);
            var html = [];
            html.push('<a class="ui_menu-indicator" href="' + liOpts.url + '">');
            var imgClass = 'ui_menu-icon';
            if (liOpts.icon || liOpts.fontIcon) {
                if (liOpts.fontIcon && !_IEunder6) {
                    liOpts.fontIcon.size = liOpts.fontIcon.size || 16;
                    liOpts.fontIcon.color = liOpts.fontIcon.color ||'inherit';
                    html.push('<span class="fa ui_menu-icon ' + liOpts.fontIcon.icon + '" style="color:' + liOpts.fontIcon.color + ';font-size:' + liOpts.fontIcon.size + 'px;"></span>');
                } else {
                    html.push('<span class="icon ' + imgClass + ' icon_' + liOpts.icon + '"></span>');
                }
                html.push('<span class="ui_menu-text">' + label + '</span>');
            }else{
                html.push('<span class="ui_menu-text" style="margin-left:2em;">' + label + '</span>');
            }

            if (liCul.length > 0) {
                li.attr("aria-haspopup", "true");
                html.push('<span class="icon ui_menu-popup" role="popup"></span>');
                _parseDuiMenu(target, liCul);
            }
            html.push('</a>');
            li.prepend(html.join(''));
        }
    };
    var _showChildren = function (target, li) {
        var options = $.data(target[0], _cacheName).options;
        if (li && li.length > 0) {
            var li_child_ul = li.children("ul").eq(0);
            var left = li.width();
            if ((2 * left + li.offset().left) > document.documentElement.clientWidth) { //当右边距离过短的时候会将提示框调整到左边
                left = -left;
            }
            li_child_ul.css({minWidth: options.minWidth, left: left});
            li_child_ul.show();

            li_child_ul.children().each(function (index, li) {
                var lic = $(this);
                if (lic.find("span:first").hasClass('ui_menu-item-sep')) {
                    lic.find("span:first").width('98%'); //分隔条宽度
                } else {
                    if (li_child_ul.width() > options.maxWidth) {
                        li_child_ul.width(options.maxWidth);
                    } else {
                        if (li_child_ul.attr('hasShow') == undefined) {
                            li_child_ul.width(li_child_ul.find('li:eq(0)>a:eq(0)').width() + 15);
                            li_child_ul.attr('hasShow', true);
                        }
                    }
                    lic.find("span.ui_menu-text").width(lic.width() - 45);
                }
            });
        }
    };
    var _bindLiEvent = function (target, li) {
        var options = $.data(target[0], _cacheName).options;
        var lic = $(li);
        var item = $.data(target[0], lic[0].id); //bug
        lic.unbind('.menuItem')
            .bind("mouseenter.menuItem", function () {
                var self_li = $(this);
                var width = self_li.parent().width();
                self_li.addClass("ui_menu-item-hover");
                if (_IE && webUI_browser().version == 9) { //解决bug AOM-576
                    self_li.parent().width(width);
                }
                if (self_li.attr("aria-haspopup")) {
                    setTimeout(function () {
                        _showChildren(target, self_li);
                    }, 200);
                }
            })
            .bind("mouseleave.menuItem", function () {
                var self_li = $(this);
                self_li.removeClass("ui_menu-item-hover");
                setTimeout(function () {
                    self_li.children("ul").hide();
                }, 200);
            })
            .bind("click.menuItem", function (event) {
                if (options.onSelect) {
                    options.onSelect.call(target, item, event);
                }
                event.stopPropagation();
            });
    };

    var _bindEvent = function (target) {
        var uls = target.find("ul"),
            lis = target.find("li");
        for (var i = 0; i < lis.length; i++) {
            if (!$(lis[i]).hasClass("ui_menu-disabled") && !$(lis[i]).hasClass("ui_menu-sep-li")) {
                _bindLiEvent(target, lis[i]);
            }
        }
        for (var j = 0; j < uls.length; j++) {
            $(uls[j]).bind("mouseleave.menuContainer", function () {
                var ul = $(this);
                if (ul.parent().attr("aria-haspopup") == "true") {
                    ul.hide();
                }
            });
        }
    };

    var _hide = function (e) {
        var target = e.data;
        if($(e.target).closest(target).length == 0) {
            target.find("ul").css("display", "none");
            target.find("li.ui_menu-item-hover").each(function (index, item) {
                $(item).removeClass("ui_menu-item-hover");
            });
            target.hide();
            $(document).unbind('mousedown.uiMenu');
        }
    };
})(jQuery);
